package com.example.emos.api.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.example.emos.api.common.util.PageUtils;
import com.example.emos.api.db.dao.TbAmectDao;
import com.example.emos.api.db.pojo.TbAmect;
import com.example.emos.api.exception.EmosException;
import com.example.emos.api.pay.PayHelper;
import com.example.emos.api.pay.PayState;
import com.example.emos.api.service.AmectService;
import com.example.emos.api.websocket.WebSocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class AmectServiceImpl implements AmectService {
    @Autowired
    private TbAmectDao amectDao;
    @Autowired
    private PayHelper payHelper;
    @Autowired
    private WebSocket webSocket;

    @Override
    public PageUtils searchAmectByPage(HashMap param) {
        ArrayList<HashMap> list = amectDao.searchAmectByPage(param);
        long count = amectDao.searchAmectCount(param);
        int start = (Integer) param.get("start");
        int length = (Integer) param.get("length");
        PageUtils pageUtils = new PageUtils(list, count, start, length);
        return pageUtils;
    }

    @Override
    @Transactional
    public int insert(ArrayList<TbAmect> list) {
        list.forEach(one -> {
            amectDao.insert(one);
        });
        return list.size();
    }

    @Override
    public HashMap searchById(int id) {
        return amectDao.searchById(id);
    }

    @Override
    public int update(HashMap param) {
        return amectDao.update(param);
    }

    @Override
    public int deleteAmectByIds(Integer[] ids) {
        return amectDao.deleteAmectByIds(ids);
    }

    /**
     * 向微信发起下单请求，取得返回的二维码付款地址
     * 将二维码付款地址缓存到redis，时间为10分钟
     */
    @Override
    public String createNativeAmectPayOrder(HashMap param) {
        int userId = MapUtil.getInt(param, "userId");
        int amectId = MapUtil.getInt(param, "amectId");
        String key = "emos.pay.url." + userId + amectId;
        String qrCodeBase64;
        HashMap map = amectDao.searchAmectByCondition(param);
        if (map != null && map.size() > 0) {
            String amount = new BigDecimal(MapUtil.getStr(map, "amount")).multiply(new BigDecimal("100")).intValue() + "";
            Map<String, String> payMap = payHelper.createPayUrl(String.valueOf(map.get("uuid")), amount, "黑马商城");
            String codeUrl = payMap.get("codeUrl");
            String prepayId = payMap.get("prepayId");
            if (StrUtil.isNotBlank(prepayId)) {
                param.clear();
                param.put("prepayId", prepayId);
                param.put("amectId", amectId);
                int rows = amectDao.updatePrepayId(param);
                if (rows != 1) {
                    throw new EmosException("更新罚款单的支付订单ID失败");
                }
                QrConfig qrConfig = new QrConfig();
                qrConfig.setWidth(255);
                qrConfig.setHeight(255);
                qrConfig.setMargin(2);
                qrCodeBase64 = QrCodeUtil.generateAsBase64(codeUrl, qrConfig, "jpg");
                return qrCodeBase64;
            } else {
                throw new EmosException("创建支付订单失败");
            }
        } else {
            throw new EmosException("没有找到罚款单");
        }
    }

    /**
     * 完成对xml数据的校验
     *
     * @param result 支付成功后微信返回xml数据序列化后的map
     */
    @Override
    public void handleNotify(Map<String, String> result) throws Exception {
        String outTradeNoStr = result.get("out_trade_no"); //订单编号
        String totalFeeStr = result.get("total_fee"); //应付金额
        if (StrUtil.isBlank(outTradeNoStr) || StrUtil.isBlank(totalFeeStr)) {
            // 抛出解析数据失败的异常
            throw new EmosException("解析数据失败异常");
        }

        //1、根据通信、业务标识判断微信下单是否成功,若不成功则抛异常
        payHelper.isSuccess(outTradeNoStr, result);
        //2、校验签名,若不成功则抛异常
        payHelper.validSign(result);

        //3、校验应付金额
        HashMap hashMap = amectDao.searchByUuid(outTradeNoStr);
        // 1分钱
        String amount = new BigDecimal(MapUtil.getStr(hashMap, "amount")).multiply(new BigDecimal("100")).intValue() + "";
        if (!totalFeeStr.equals(amount)) {  //应付金额不符
            //抛出应付金额不符异常
            throw new EmosException("应付金额不正确");
        }

        //4、修改订单状态为已付款
        HashMap param = new HashMap(){{
            put("uuid", outTradeNoStr);
            put("status", 2);
        }};
        int rows = amectDao.updateStatus(param);
        //修改订单状态失败
        if (rows != 1) {
            //抛出修改订单状态失败异常
            throw new EmosException("修改订单状态失败");
        }
        // 获取当前会话的token值
        String userId = MapUtil.getStr(hashMap, "userId");
        String token = StpUtil.getTokenValueByLoginId(userId);
        // websocket向前端页面推送付款结果
        webSocket.sendMessage("付款成功", token);
    }

    @Override
    public void searchNativeAmectPayResult(HashMap param) {
        HashMap map = amectDao.searchAmectByCondition(param);
        if (MapUtil.isNotEmpty(map)) {
            String uuid = MapUtil.getStr(map, "uuid");
            String amount = new BigDecimal(MapUtil.getStr(map, "amount")).multiply(new BigDecimal("100")).intValue() + "";
            PayState payState = payHelper.queryOrder(uuid, amount);
            if (payState.equals(PayState.SUCCESS)) {
                // 修改订单状态为支付成功
                param.clear();
                param = new HashMap(){{
                    put("uuid", uuid);
                    put("status", 2);
                }};
                int rows = amectDao.updateStatus(param);
                if (rows != 1) {
                    //抛出修改订单状态失败异常
                    throw new EmosException("修改订单状态失败");
                }
            }
        }
    }
}
